using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.DependencyInjection;

namespace CKY.AgentPlatform.RateLimiting
{
    /// <summary>
    /// 限流特性
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public class RateLimitAttribute : Attribute, IAsyncActionFilter, ITransientDependency
    {
        private readonly DistributedCacheService _cacheService;
        private readonly ILogger<RateLimitAttribute> _logger;
        private readonly RateLimitOptions _options;

        public string EndpointKey { get; set; }
        public int MaxRequests { get; set; } = 100;
        public int WindowMinutes { get; set; } = 15;
        public string Policy { get; set; }

        public RateLimitAttribute()
        {
        }

        public RateLimitAttribute(string endpointKey)
        {
            EndpointKey = endpointKey;
        }

        public RateLimitAttribute(string endpointKey, int maxRequests, int windowMinutes)
        {
            EndpointKey = endpointKey;
            MaxRequests = maxRequests;
            WindowMinutes = windowMinutes;
        }

        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            // 获取服务
            _cacheService = context.HttpContext.RequestServices.GetService<DistributedCacheService>();
            _logger = context.HttpContext.RequestServices.GetService<ILogger<RateLimitAttribute>>();
            _options = context.HttpContext.RequestServices.GetService<IOptions<RateLimitOptions>>()?.Value;

            if (_cacheService == null || _options == null)
            {
                await next();
                return;
            }

            // 获取客户端标识符
            var clientIdentifier = await GetClientIdentifierAsync(context.HttpContext);
            
            // 检查是否在白名单中
            if (IsInWhitelist(context.HttpContext))
            {
                await next();
                return;
            }

            // 检查限流
            if (await IsRateLimitedAsync(clientIdentifier))
            {
                await ReturnRateLimitResponseAsync(context);
                return;
            }

            // 记录请求
            await RecordRequestAsync(clientIdentifier, context.HttpContext);

            await next();
        }

        private async Task<string> GetClientIdentifierAsync(HttpContext context)
        {
            // 优先使用用户ID
            if (context.User.Identity.IsAuthenticated)
            {
                var userId = context.User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value;
                if (!string.IsNullOrEmpty(userId))
                {
                    return $"user:{userId}";
                }
            }

            // 使用IP地址
            var ipAddress = GetClientIpAddress(context);
            
            // 如果启用API密钥，尝试获取API密钥
            if (_options.EnableApiKeyAuth)
            {
                var apiKey = GetApiKey(context);
                if (!string.IsNullOrEmpty(apiKey))
                {
                    return $"api_key:{apiKey}";
                }
            }

            return $"ip:{ipAddress}";
        }

        private string GetClientIpAddress(HttpContext context)
        {
            var forwardedFor = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
            var realIp = context.Request.Headers["X-Real-IP"].FirstOrDefault();
            
            if (!string.IsNullOrEmpty(forwardedFor))
            {
                return forwardedFor.Split(',')[0].Trim();
            }

            if (!string.IsNullOrEmpty(realIp))
            {
                return realIp;
            }

            return context.Connection.RemoteIpAddress?.ToString() ?? "unknown";
        }

        private string GetApiKey(HttpContext context)
        {
            if (_options.EnableApiKeyAuth)
            {
                // 从Header获取
                if (context.Request.Headers.TryGetValue(_options.ApiKeyHeaderName, out var apiKey))
                {
                    return apiKey;
                }

                // 从查询参数获取
                return context.Request.Query[_options.ApiKeyQueryParam].FirstOrDefault();
            }

            return null;
        }

        private bool IsInWhitelist(HttpContext context)
        {
            var clientIp = GetClientIpAddress(context);
            
            // 检查IP白名单
            if (_options.IPWhitelist?.Contains(clientIp) == true)
            {
                return true;
            }

            // 检查路径白名单
            var path = context.Request.Path.Value;
            if (_options.PathWhitelist?.Any(pattern => 
                System.Text.RegularExpressions.Regex.IsMatch(path, pattern)) == true)
            {
                return true;
            }

            // 检查用户白名单
            if (context.User.Identity.IsAuthenticated)
            {
                var username = context.User.Identity.Name;
                if (_options.UserWhitelist?.Contains(username) == true)
                {
                    return true;
                }
            }

            return false;
        }

        private async Task<bool> IsRateLimitedAsync(string clientIdentifier)
        {
            var endpointKey = string.IsNullOrEmpty(EndpointKey) ? 
                $"{clientIdentifier}:custom" : 
                $"{clientIdentifier}:{EndpointKey}";
            
            var cacheKey = $"rate_limit:{endpointKey}";
            var currentCount = await _cacheService.GetLongAsync(cacheKey);
            
            if (currentCount >= MaxRequests)
            {
                _logger.LogWarning("端点被限流: {ClientIdentifier}, 端点: {EndpointKey}, 当前请求数: {Count}", 
                    clientIdentifier, EndpointKey, currentCount);
                return true;
            }

            return false;
        }

        private async Task RecordRequestAsync(string clientIdentifier, HttpContext context)
        {
            var endpointKey = string.IsNullOrEmpty(EndpointKey) ? 
                $"{clientIdentifier}:custom" : 
                $"{clientIdentifier}:{EndpointKey}";
            
            var cacheKey = $"rate_limit:{endpointKey}";
            await _cacheService.IncrementAsync(cacheKey);
        }

        private async Task ReturnRateLimitResponseAsync(ActionExecutingContext context)
        {
            context.HttpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests;
            context.HttpContext.Response.Headers["Retry-After"] = WindowMinutes.ToString();
            context.HttpContext.Response.Headers["X-RateLimit-Limit"] = MaxRequests.ToString();
            context.HttpContext.Response.Headers["X-RateLimit-Remaining"] = "0";
            context.HttpContext.Response.Headers["X-RateLimit-Reset"] = 
                DateTime.UtcNow.AddMinutes(WindowMinutes).ToString("yyyy-MM-ddTHH:mm:ssZ");

            var response = new RateLimitResponse
            {
                Message = "请求过于频繁，请稍后再试",
                RetryAfter = WindowMinutes,
                Limit = MaxRequests,
                Window = WindowMinutes
            };

            context.Result = new JsonResult(response)
            {
                StatusCode = StatusCodes.Status429TooManyRequests
            };

            _logger.LogWarning("返回限流响应: {ClientIdentifier}, 端点: {EndpointKey}", 
                await GetClientIdentifierAsync(context.HttpContext), EndpointKey);
        }
    }

    /// <summary>
    /// API密钥授权特性
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public class ApiKeyAuthorizeAttribute : Attribute, IAsyncActionFilter, ITransientDependency
    {
        private readonly RateLimitOptions _options;
        private readonly ILogger<ApiKeyAuthorizeAttribute> _logger;

        public string Policy { get; set; }
        public string RequiredRole { get; set; }

        public ApiKeyAuthorizeAttribute()
        {
        }

        public ApiKeyAuthorizeAttribute(string policy)
        {
            Policy = policy;
        }

        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            _options = context.HttpContext.RequestServices.GetService<IOptions<RateLimitOptions>>()?.Value;
            _logger = context.HttpContext.RequestServices.GetService<ILogger<ApiKeyAuthorizeAttribute>>();

            if (_options == null || !_options.EnableApiKeyAuth)
            {
                await next();
                return;
            }

            var apiKey = GetApiKey(context.HttpContext);
            if (string.IsNullOrEmpty(apiKey))
            {
                await ReturnUnauthorizedResponseAsync(context, "缺少API密钥");
                return;
            }

            if (!IsValidApiKey(apiKey))
            {
                await ReturnUnauthorizedResponseAsync(context, "无效的API密钥");
                return;
            }

            if (!string.IsNullOrEmpty(Policy) && !HasPolicyPermission(apiKey, Policy))
            {
                await ReturnForbiddenResponseAsync(context, "权限不足");
                return;
            }

            await next();
        }

        private string GetApiKey(HttpContext context)
        {
            // 从Header获取
            if (context.Request.Headers.TryGetValue(_options.ApiKeyHeaderName, out var apiKey))
            {
                return apiKey;
            }

            // 从查询参数获取
            return context.Request.Query[_options.ApiKeyQueryParam].FirstOrDefault();
        }

        private bool IsValidApiKey(string apiKey)
        {
            return _options.ValidApiKeys?.Contains(apiKey) == true;
        }

        private bool HasPolicyPermission(string apiKey, string policy)
        {
            // 简化实现，实际项目中可以从数据库或配置中获取API密钥权限
            return true;
        }

        private async Task ReturnUnauthorizedResponseAsync(ActionExecutingContext context, string message)
        {
            context.HttpContext.Response.StatusCode = StatusCodes.Status401Unauthorized;
            
            var response = new ApiResponse
            {
                Success = false,
                Message = message,
                Timestamp = DateTime.UtcNow
            };

            context.Result = new JsonResult(response)
            {
                StatusCode = StatusCodes.Status401Unauthorized
            };

            _logger.LogWarning("返回未授权响应: {Message}", message);
        }

        private async Task ReturnForbiddenResponseAsync(ActionExecutingContext context, string message)
        {
            context.HttpContext.Response.StatusCode = StatusCodes.Status403Forbidden;
            
            var response = new ApiResponse
            {
                Success = false,
                Message = message,
                Timestamp = DateTime.UtcNow
            };

            context.Result = new JsonResult(response)
            {
                StatusCode = StatusCodes.Status403Forbidden
            };

            _logger.LogWarning("返回禁止访问响应: {Message}", message);
        }
    }

    /// <summary>
    /// IP白名单特性
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public class IpWhitelistAttribute : Attribute, IAsyncActionFilter, ITransientDependency
    {
        private readonly RateLimitOptions _options;
        private readonly ILogger<IpWhitelistAttribute> _logger;

        public string[] AllowedIPs { get; set; }

        public IpWhitelistAttribute(params string[] allowedIPs)
        {
            AllowedIPs = allowedIPs;
        }

        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            _options = context.HttpContext.RequestServices.GetService<IOptions<RateLimitOptions>>()?.Value;
            _logger = context.HttpContext.RequestServices.GetService<ILogger<IpWhitelistAttribute>>();

            if (_options == null)
            {
                await next();
                return;
            }

            var clientIp = GetClientIpAddress(context.HttpContext);
            
            if (!IsAllowedIP(clientIp))
            {
                await ReturnForbiddenResponseAsync(context, $"IP地址 {clientIp} 不在白名单中");
                return;
            }

            await next();
        }

        private string GetClientIpAddress(HttpContext context)
        {
            var forwardedFor = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
            var realIp = context.Request.Headers["X-Real-IP"].FirstOrDefault();
            
            if (!string.IsNullOrEmpty(forwardedFor))
            {
                return forwardedFor.Split(',')[0].Trim();
            }

            if (!string.IsNullOrEmpty(realIp))
            {
                return realIp;
            }

            return context.Connection.RemoteIpAddress?.ToString() ?? "unknown";
        }

        private bool IsAllowedIP(string clientIp)
        {
            // 检查特性中配置的IP
            if (AllowedIPs?.Contains(clientIp) == true)
            {
                return true;
            }

            // 检查全局配置的IP白名单
            return _options.IPWhitelist?.Contains(clientIp) == true;
        }

        private async Task ReturnForbiddenResponseAsync(ActionExecutingContext context, string message)
        {
            context.HttpContext.Response.StatusCode = StatusCodes.Status403Forbidden;
            
            var response = new ApiResponse
            {
                Success = false,
                Message = message,
                Timestamp = DateTime.UtcNow
            };

            context.Result = new JsonResult(response)
            {
                StatusCode = StatusCodes.Status403Forbidden
            };

            _logger.LogWarning("返回禁止访问响应: {Message}", message);
        }
    }

    /// <summary>
    /// 基础响应类
    /// </summary>
    public class ApiResponse
    {
        public bool Success { get; set; }
        public string Message { get; set; }
        public DateTime Timestamp { get; set; }
        public object Data { get; set; }
    }
}